package com.nuoniu.sibanyun.service.po.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.nuoniu.sibanyun.common.exception.NuoNiuException;
import com.nuoniu.sibanyun.common.result.HttpResult;
import com.nuoniu.sibanyun.entity.bo.VoucherDetailBo;
import com.nuoniu.sibanyun.entity.bo.VoucherMainBo;
import com.nuoniu.sibanyun.entity.bo.VoucherSearchBo;
import com.nuoniu.sibanyun.entity.erp.ErpNumberSet;
import com.nuoniu.sibanyun.entity.po.VPoPurchaseOrderDetail;
import com.nuoniu.sibanyun.entity.po.VPoPurchaseOrderMain;
import com.nuoniu.sibanyun.entity.po.VPurchaseArrivalDetail;
import com.nuoniu.sibanyun.entity.po.VPurchaseArrivalMain;
import com.nuoniu.sibanyun.entity.production.VProductionPlanMain;
import com.nuoniu.sibanyun.entity.so.VSaleDeliveryDetail;
import com.nuoniu.sibanyun.entity.so.VSaleDeliveryMain;
import com.nuoniu.sibanyun.mapper.erp.ErpNumberSetMapper;
import com.nuoniu.sibanyun.mapper.po.VPoPurchaseOrderMainMapper;
import com.nuoniu.sibanyun.service.crm.ICrmGoodsService;
import com.nuoniu.sibanyun.service.erp.IErpAccountService;
import com.nuoniu.sibanyun.service.erp.IErpNumberSetService;
import com.nuoniu.sibanyun.service.erp.IErpVoucherDesignService;
import com.nuoniu.sibanyun.service.po.IVPoPurchaseOrderDetailService;
import com.nuoniu.sibanyun.service.po.IVPoPurchaseOrderMainService;
import com.nuoniu.sibanyun.service.utils.ErpUtils;
import com.nuoniu.sibanyun.userThread.UserInfo;
import com.nuoniu.sibanyun.userThread.UserThreadLocal;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 采购订单主表 服务实现类
 * </p>
 *
 * @author baiqiang
 * @since 2020-11-16
 */
@Service
public class VPoPurchaseOrderMainServiceImpl extends ServiceImpl<VPoPurchaseOrderMainMapper, VPoPurchaseOrderMain> implements IVPoPurchaseOrderMainService {

    @Autowired
    private IErpNumberSetService numberSetService;
    @Autowired
    private ErpNumberSetMapper numberSetMapper;
    @Autowired
    private IVPoPurchaseOrderDetailService orderDetailService;
    @Autowired
    private IErpAccountService erpAccountService;
    @Autowired
    private IErpVoucherDesignService erpVoucherDesignService;
    @Autowired
    private ICrmGoodsService crmGoodsService;

    @Override
    public String getCode(Integer companyId) {
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        ErpNumberSet numberSet = numberSetMapper.getByCode("PurchaseOrder", companyId, currentAccountId);
        String dateStr = numberSet.getMedian() == 1 ? "%Y-%m-%d" : "%Y-%m";
        String code = baseMapper.getNewestCode(companyId, dateStr);
        return numberSetService.getCode(numberSet, code);
    }

    @Override
    public List<VPoPurchaseOrderMain> getBySourceCode(String sourceVoucherCode) {
        return baseMapper.getBySourceCode(sourceVoucherCode, UserThreadLocal.get().getCompanyId());
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void saveOrder(VPoPurchaseOrderMain orderMain) {
        Boolean isNewMain = false;
        List<VPoPurchaseOrderDetail> orderDetailList = orderMain.getOrderDetailList();
        if(null == orderDetailList)throw new NuoNiuException("单据明细不能为空");
        Long mainId = orderMain.getId();
        UserInfo userInfo = UserThreadLocal.get();
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        VPoPurchaseOrderMain oldVPoPurchaseOrderMain = null;
        if(mainId == null) {
            isNewMain = true;
            String code = getCode(userInfo.getCompanyId());
            if(code == null) {
                new NuoNiuException("单据编号已上限");
            }
            boolean isHaveId = orderDetailList.stream().anyMatch(f -> null != f.getId());
            if(isHaveId)throw new NuoNiuException("单据明细错误：不能新增已经存在的明细记录");
            orderMain.setAccountId(currentAccountId);
            orderMain.setVoucherState(-1);
            orderMain.setVoucherCode(code);
            orderMain.setCompanyId(userInfo.getCompanyId());
            orderMain.setCreateUserId(userInfo.getUserId());
            orderMain.setCreateUserName(userInfo.getRealName());
            orderMain.setCumExecuteQuantity(new BigDecimal(0.0));
        }else {
            //校验详情（详情不能有其他单据的明细ID）
            boolean isHaveErrorId = orderDetailList.stream().anyMatch(f -> null != f.getOrderId() && !mainId.toString().equals(f.getOrderId().toString()));
            if(isHaveErrorId)throw new NuoNiuException("单据明细错误：不能修改其他单据的明细记录");
            oldVPoPurchaseOrderMain = getById(mainId);
            /**************  修改权限 *******************/
            if(!crmGoodsService.isHaveOperationRight(oldVPoPurchaseOrderMain.getCreateUserId().longValue())){
                throw new NuoNiuException("你没有权限操作该记录");
            }
            Integer voucherState = oldVPoPurchaseOrderMain.getVoucherState();
            if(null != voucherState && voucherState > 0){
                throw new NuoNiuException("已审核,不能修改");
            }
            orderMain.setUpdateUserId(userInfo.getUserId());
            orderMain.setUpdateDate(LocalDateTime.now());
            orderMain.setAccountId(oldVPoPurchaseOrderMain.getAccountId());
            orderMain.setSourceVoucherCode(oldVPoPurchaseOrderMain.getSourceVoucherCode());
            orderMain.setSourceVoucherId(oldVPoPurchaseOrderMain.getSourceVoucherId());
            orderMain.setSourceVoucherType(oldVPoPurchaseOrderMain.getSourceVoucherType());
            orderMain.setSourceVoucherDate(oldVPoPurchaseOrderMain.getSourceVoucherDate());
            //不可更新字段
            orderMain.setVoucherCode(null);
        }

        // 校验 明细数量
        boolean isOk = orderMain.getOrderDetailList().stream().anyMatch(f -> null == f.getBaseQuantity() || !(f.getBaseQuantity().compareTo(BigDecimal.ZERO) > 0));
        if(isOk)throw new NuoNiuException("明细数量必须大于0");
        //计算 明细物料 总数
        BigDecimal totalQuantity =  orderMain.getOrderDetailList().stream().map(VPoPurchaseOrderDetail::getBaseQuantity).reduce(BigDecimal.ZERO,BigDecimal::add);
        orderMain.setTotalQuantity(totalQuantity.abs());

        Boolean result = this.saveOrUpdate(orderMain);
        if(result) {
            List<Long> detailIds = new ArrayList<>();
            orderDetailList.forEach(p -> {
                p.setOrderId(orderMain.getId().intValue());
                p.setCompanyId(userInfo.getCompanyId());
                p.setAccountId(orderMain.getAccountId());
                p.setSourceVoucherCode(orderMain.getSourceVoucherCode());
                p.setSourceVoucherType(orderMain.getSourceVoucherType());
                p.setSourceVoucherDate(orderMain.getSourceVoucherDate());
                p.setSourceVoucherId(orderMain.getSourceVoucherId());
                if(p.getId() != null) {
                    detailIds.add(p.getId());
                }
            });
            boolean isDealDelete =  false;
            if(null != mainId){
                //删除明细
                QueryWrapper wrapper = new QueryWrapper();
                wrapper.eq("order_id", mainId);
                if(detailIds != null && detailIds.size() > 0) {
                    wrapper.notIn("id", detailIds);
                }
                isDealDelete = orderDetailService.remove(wrapper);
            }
            //保存单据明细表
            orderDetailService.saveOrUpdateBatch(orderDetailList);
            // *** 如果 来源订单不为空,校验
            if(null != orderMain.getSourceVoucherId()){
                if(orderMain.getSourceVoucherType().equals("PurchaseRequisition")) {
                    if(isDealDelete)throw new NuoNiuException("有来源的单据不能删除明细");
                    if(!"PurchaseRequisition".equals(orderMain.getSourceVoucherType()))throw new NuoNiuException("采购订单的来源单，只能是请购单");
                    VoucherMainBo voucherMainBo = new VoucherMainBo();
                    BeanUtils.copyProperties(orderMain,voucherMainBo);
                    voucherMainBo.setIsNewMain(isNewMain);
                    List<VoucherDetailBo> voucherDetailBos = new ArrayList<>();
                    orderDetailList.forEach(detail->{
                        VoucherDetailBo voucherDetailBo = new VoucherDetailBo();
                        voucherDetailBos.add(voucherDetailBo);
                        BeanUtils.copyProperties(detail,voucherDetailBo);
                    });
                    VoucherSearchBo voucherSearchBo = new VoucherSearchBo();
                    voucherSearchBo.setSourceVoucherId(orderMain.getSourceVoucherId());
                    voucherSearchBo.setSourceVoucherType(orderMain.getSourceVoucherType());
                    voucherSearchBo.setVoucherId(orderMain.getId().intValue());
                    voucherSearchBo.setVoucherType("PurchaseOrder");
                    erpVoucherDesignService.calculateSourceVoucher(voucherMainBo,voucherDetailBos,voucherSearchBo);
                } else if(orderMain.getSourceVoucherType().equals("MasterProductionSchedule")) {

                }
            }


        }
    }

    @Override
    public Set<Long> saveOrderForVendor(VPoPurchaseOrderMain orderMain) throws InterruptedException {
        Set<Long> idSet = new HashSet<>();
        Map<Integer,List<VPoPurchaseOrderDetail>> detailMap = new HashMap<>();
        List<VPoPurchaseOrderDetail> orderDetailList = orderMain.getOrderDetailList();
        orderDetailList.forEach(detail->{
            Integer keyId = detail.getVendorId();
            VPoPurchaseOrderDetail newDetail = new VPoPurchaseOrderDetail();
            BeanUtils.copyProperties(detail,newDetail);
            List<VPoPurchaseOrderDetail> newDetailList = detailMap.get(keyId);
            if(null == newDetailList){
                newDetailList = new ArrayList<>();
                detailMap.put(keyId,newDetailList);
            }
            newDetailList.add(newDetail);
        });

        for (Integer keyId : detailMap.keySet()) {
            VPoPurchaseOrderMain newMain = new VPoPurchaseOrderMain();
            BeanUtils.copyProperties(orderMain,newMain);
            List<VPoPurchaseOrderDetail> vInOutRecordDetails = detailMap.get(keyId);
            BigDecimal totalQuantity = vInOutRecordDetails.stream().map(VPoPurchaseOrderDetail::getBaseQuantity).reduce(BigDecimal.ZERO,BigDecimal::add);
            newMain.setTotalQuantity(totalQuantity.abs());
            VPoPurchaseOrderDetail detail = vInOutRecordDetails.get(0);
            Integer vendorId = detail.getVendorId();
            String vendorName = detail.getVendorName();
            newMain.setVendorId(vendorId);
            newMain.setVendorName(vendorName);
            newMain.setOrderDetailList(vInOutRecordDetails);
            saveOrder(newMain);
            Thread.sleep(100);
            idSet.add(newMain.getId());
        }
        return idSet;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void deleteById(Long id) {
        UserInfo userInfo = UserThreadLocal.get();
        VPoPurchaseOrderMain purchaseOrder = getById(id);
        if(purchaseOrder == null) {
            throw new NuoNiuException("删除失败，记录不存在");
        }
        /**************  修改权限 *******************/
        if(!crmGoodsService.isHaveOperationRight(purchaseOrder.getCreateUserId().longValue())){
            throw new NuoNiuException("你没有权限操作该记录");
        }
        BigDecimal cumExecuteQuantity = purchaseOrder.getCumExecuteQuantity();
        if(null != cumExecuteQuantity && cumExecuteQuantity.compareTo(BigDecimal.ZERO) > 0){
            throw new NuoNiuException("采购订单单据已经生成出库单据，不能删除");
        }
        //如果 来源订单 不为空
        if(null != purchaseOrder.getSourceVoucherId()){
            //查询 单据明细
            List<VPoPurchaseOrderDetail> orderDetails = orderDetailService.getOrderDetails(id);
            VoucherMainBo voucherMainBo = new VoucherMainBo();
            BeanUtils.copyProperties(purchaseOrder,voucherMainBo);
            List<VoucherDetailBo> voucherDetailBos = new ArrayList<>();
            orderDetails.forEach(detail->{
                VoucherDetailBo voucherDetailBo = new VoucherDetailBo();
                voucherDetailBos.add(voucherDetailBo);
                BeanUtils.copyProperties(detail,voucherDetailBo);
            });
            VoucherSearchBo voucherSearchBo = new VoucherSearchBo();
            voucherSearchBo.setCalculateType(2);
            voucherSearchBo.setSourceVoucherId(purchaseOrder.getSourceVoucherId());
            voucherSearchBo.setSourceVoucherType(purchaseOrder.getSourceVoucherType());
            voucherSearchBo.setVoucherId(purchaseOrder.getId().intValue());
            voucherSearchBo.setVoucherType("PurchaseOrder");
            erpVoucherDesignService.calculateSourceVoucher(voucherMainBo,voucherDetailBos,voucherSearchBo);
        }
        removeById(id);
        orderDetailService.removeByOrderId(id);
    }

    @Override
    public void submit(Long id, Integer status) {
        if(null == id || null == status || (null != status && (status > 0 || status < -1 )))throw new NuoNiuException("参数错误");
        UserInfo userInfo = UserThreadLocal.get();
        VPoPurchaseOrderMain poPurchaseOrderMain = this.getById(id);
        if( null == poPurchaseOrderMain)throw new NuoNiuException("记录不存在");
        //校验状态
        Integer voucherState = poPurchaseOrderMain.getVoucherState();
        if(status == 0){
            if (voucherState > -1)throw new NuoNiuException("该单据已经提交");
        }else if(status == -1){
            if (voucherState > 0)throw new NuoNiuException("该单据已经审核,请先弃审");
        }
        //提交
        poPurchaseOrderMain.setVoucherState(status);
        poPurchaseOrderMain.setSubmitDate(LocalDateTime.now());
        poPurchaseOrderMain.setSubmitUserId(userInfo.getUserId());
        poPurchaseOrderMain.setSubmitUserName(userInfo.getRealName());
        this.updateById(poPurchaseOrderMain);
    }

    @Override
    public void examine(Long id, Integer status) {
        UserInfo userInfo = UserThreadLocal.get();
        VPoPurchaseOrderMain poPurchaseOrderMain = this.getById(id);
        if(poPurchaseOrderMain == null) {
            throw new NuoNiuException("单据不存在");
        }

        if(poPurchaseOrderMain.getClosedState() != null && poPurchaseOrderMain.getClosedState().equals(0)) {
            throw new NuoNiuException("单据已关闭");
        }

        Integer voucherState = poPurchaseOrderMain.getVoucherState();
        BigDecimal cumExecuteQuantity = poPurchaseOrderMain.getCumExecuteQuantity();
        /** 统一校验 审核状态*/
        ErpUtils.checkExamineStatus(voucherState,status,cumExecuteQuantity);
        poPurchaseOrderMain.setVoucherState(status);
        poPurchaseOrderMain.setReviewerUserId(userInfo.getUserId());
        poPurchaseOrderMain.setReviewerUserName(userInfo.getRealName());
        poPurchaseOrderMain.setReviewerDate(LocalDateTime.now());
        this.updateById(poPurchaseOrderMain);
    }

    @Override
    public void closed(Long id, Integer status) {
        if(status == null || id == null) {
            throw new NuoNiuException("参数错误！！！");
        }

        UserInfo userInfo = UserThreadLocal.get();
        VPoPurchaseOrderMain poPurchaseOrderMain = this.getById(id);
        if(status.equals(1)) {
            if(poPurchaseOrderMain.getReleaseState().equals(2)) {
                throw new NuoNiuException("已生单不能打开");
            }
        } else {
            if(!poPurchaseOrderMain.getVoucherState().equals(1)) {
                throw new NuoNiuException("已审核状态的订单才能关闭");
            }
        }

        poPurchaseOrderMain.setVoucherState(status);
        poPurchaseOrderMain.setClosedDate(LocalDate.now());
        poPurchaseOrderMain.setCloserId(userInfo.getUserId());
        poPurchaseOrderMain.setCloserName(userInfo.getUserName());
        poPurchaseOrderMain.setId(id);
        updateById(poPurchaseOrderMain);
    }

}
